#!/usr/bin/env gosh
(use srfi-1)
(use sxml.ssax)
(use sxml.serializer)
(use sxml.tools)
(use sxml.sxpath)
(use gauche.process)
(use gauche.parseopt)

(define (main args)
  (let-args (cdr args)
      ((option-n "n|node=s" "")
       (option-k "k|key=s" "")
       (sort-opt "o|option=s" "")
       . file)
    (define sxml (if (null? file)
		   (ssax:xml->sxml (current-input-port) '())
		   (call-with-input-file (car file) (cut ssax:xml->sxml <> '()))))
    (let* ((nodes ((sxpath option-n) sxml))
	   (keys  (map (lambda (x)
			 (or ((if-car-sxpath option-k) x) ""))
		       nodes))
	   (ht (make-hash-table 'string=?)))
      (for-each (lambda (i key)
		  (hash-table-push! ht key i))
		(reverse (iota (length keys))) (reverse keys))
      (let* ((nodes-vec (list->vector nodes))
	     (sorted-nodes  (map (cut vector-ref nodes-vec <>)
				 (map (lambda (x)
					(hash-table-pop! ht x))
				      (run-cmd (string-append "sort " sort-opt) keys))))
	     (removed-nodes (map (cut vector-ref nodes-vec <>)
				 (concatenate (hash-table-map ht (lambda (_ value) value)))))
	     (copy-sorted-nodes (map deep-copy-sxml sorted-nodes)))
	(for-each (lambda (node)
		    (sxml:change-content! node '()))
		  nodes)
	(for-each (lambda (old new)
		    (sxml:change-content! old (sxml:content (car (sxml:content new)))))
		  nodes copy-sorted-nodes)
	(srl:sxml->xml sxml (current-output-port)))))
  (exit 0))

(define (deep-copy-sxml sxml)
  (call-with-input-string (call-with-output-string (cut srl:sxml->xml sxml <>)) (cut ssax:xml->sxml <> '())))

(define (run-cmd cmd keys)
 (call-with-process-io
  cmd
  (lambda (in out)
    (for-each (cut format out "~a\n" <>) keys)
    (flush out)
    (close-output-port out)
    (port->string-list in))
  :on-abnormal-exit :ignore))
